package remote

import (
	"apedge/pkg/configs"
	"apedge/pkg/protocol"
	"apedge/pkg/utils"
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"time"

	"github.com/go-playground/validator/v10"
	"github.com/mitchellh/mapstructure"
)

func PreHandler(req map[string]interface{}, reqContent interface{}) error {
	if err := Decode(req, &reqContent); err != nil {
		return err
	}
	validate := validator.New()
	err := validate.Struct(reqContent)
	if err != nil {
		return err
	}
	return nil
}

func Decode(input map[string]interface{}, result interface{}) error {
	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		Metadata: nil,
		DecodeHook: mapstructure.ComposeDecodeHookFunc(
			ToTimeHookFunc()),
		Result: result,
	})
	if err != nil {
		return err
	}

	if err := decoder.Decode(input); err != nil {
		return err
	}
	return err
}

func ToTimeHookFunc() mapstructure.DecodeHookFunc {
	return func(
		f reflect.Type,
		t reflect.Type,
		data interface{}) (interface{}, error) {
		if t != reflect.TypeOf(time.Time{}) {
			return data, nil
		}

		switch f.Kind() {
		case reflect.String:
			return time.Parse(time.RFC3339, data.(string))
		case reflect.Float64:
			return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil
		case reflect.Int64:
			return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil
		default:
			return data, nil
		}
	}
}

// // 模型详情
// func GetModelVersionDetailsFromApWorkShop(modelId int64, modelVerId int64) (*protocol.ModelVersionInfo, error) {
// 	var respBody protocol.APISuccessRsp
// 	var modelVersionInfo protocol.ModelVersionInfo
// 	var client = &http.Client{
// 		Timeout: time.Second * 10,
// 	}

// 	url := utils.GetHttpUrl(configs.Config.Relevant.ModelFactorySvc, fmt.Sprintf(ModelFactoryModelVersionUrl, modelId, modelVerId))
// 	logger.Infoln("get model version details url: ", url)
// 	req, err := http.NewRequest("GET", url, nil)
// 	if err != nil {
// 		return nil, err
// 	}

// 	resp, err := client.Do(req)
// 	if err != nil {
// 		return nil, err
// 	}

// 	err = json.NewDecoder(resp.Body).Decode(&respBody)
// 	if err != nil {
// 		return nil, err
// 	}
// 	logger.Infof("model versionId %d,  response:", modelVerId, respBody)

// 	if resp.StatusCode != 200 {
// 		return nil, fmt.Errorf("get model %d info error", modelVerId)
// 	}

// 	// err = mapstructure.Decode(respBody.Data, &modelVersionInfo)  preHandler
// 	// err = preHandler(respBody.Data.(map[string]interface{}), &modelVersionInfo)
// 	// if err != nil {
// 	// 	return nil, err
// 	// }
// 	modelVersionInfo.StoragePath = respBody.Data.(map[string]interface{})["modelVersion"].(map[string]interface{})["storagePath"].(string)
// 	return &modelVersionInfo, nil
// }

// 模型详情
func GetModelPathFromApWorkShop(modelId int64, modelVerId int64) (*protocol.ModelPathRsp, error) {
	var respBody protocol.APISuccessRsp
	var modelPathRsp protocol.ModelPathRsp
	var client = &http.Client{
		Timeout: time.Second * 10,
	}

	reqContent := protocol.ModelPathReq{
		ModelId:        modelId,
		ModelVersionId: modelVerId,
	}
	data, err := json.Marshal(reqContent)
	if err != nil {
		return nil, err
	}
	logger.Infof("model path req: %s", string(data))

	url := utils.GetHttpUrl(configs.Config.Relevant.Service.ModelFactorySvc, ModelPathInfoUrl)
	logger.Infoln("get model path url: ", url)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(&respBody)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("model check svc error %d %+v", resp.StatusCode, respBody)
	}

	if respBody.Code != 0 {
		return nil, fmt.Errorf("model check svc error %d %+v", respBody.Code, respBody.Msg)
	}

	err = mapstructure.Decode(respBody.Data, &modelPathRsp)
	if err != nil {
		return nil, err
	}

	logger.Infof("model check rsp: %+v", modelPathRsp)
	return &modelPathRsp, nil
}

// 模型检查
func ModelCheckFromApWorkShop(modelId int64, modelVerId int64, deviceType string) (*protocol.ModelCheckRsp, error) {
	var reqContent protocol.ModelCheckReq
	var respBody protocol.APISuccessRsp
	var modelCheckRsp protocol.ModelCheckRsp
	var client = &http.Client{
		Timeout: time.Second * 10,
	}

	reqContent = protocol.ModelCheckReq{
		ModelId:        modelId,
		ModelVersionId: modelVerId,
		DeviceType:     deviceType,
	}

	data, err := json.Marshal(reqContent)
	if err != nil {
		return nil, err
	}
	logger.Info("model check req: %s", string(data))

	url := utils.GetHttpUrl(configs.Config.Relevant.Service.ModelFactorySvc, ModelCheckUrl)
	logger.Infoln("model check url: ", url)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	err = json.NewDecoder(resp.Body).Decode(&respBody)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("model check svc error %d %+v", resp.StatusCode, respBody)
	}

	if respBody.Code != 0 {
		return nil, fmt.Errorf("model check svc error %d %+v", respBody.Code, respBody.Msg)
	}

	err = mapstructure.Decode(respBody.Data, &modelCheckRsp)
	if err != nil {
		return nil, err
	}

	logger.Infof("model check rsp: %+v", modelCheckRsp)
	return &modelCheckRsp, nil
}

// 模型转换
func ModelTransformApWorkShop(modelId int64, modelVerId int64, deviceType string, ServiceId string, queueName string) (*protocol.ModelTransformRsp, error) {
	var reqContent protocol.ModelTransformReq
	var rspContent protocol.ModelTransformRsp
	var respBody protocol.APISuccessRsp
	var client = &http.Client{
		Timeout: time.Second * 10,
	}

	reqContent = protocol.ModelTransformReq{
		ModelId:        modelId,
		ServiceId:      ServiceId,
		ModelVersionId: modelVerId,
		DeviceType:     deviceType,
		QueueName:      queueName,
	}

	data, err := json.Marshal(reqContent)
	if err != nil {
		return nil, err
	}
	logger.Infof("model transform req: %s", string(data))

	url := utils.GetHttpUrl(configs.Config.Relevant.Service.ModelFactorySvc, ModelTransformUrl)
	logger.Infoln("model transform url: ", url)

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Content-Type", "application/json")
	resp, err := client.Do(req)
	if err != nil {
		logger.Infoln("workshop request failed")
		return nil, err
	}
	defer resp.Body.Close()
	// logger.Errorln("----------------------------------")

	// logger.Errorf("%+v", resp.Body)
	err = json.NewDecoder(resp.Body).Decode(&respBody)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("model transform svc error %d %+v", resp.StatusCode, respBody)
	}

	if respBody.Code != 0 {
		return nil, fmt.Errorf("model transform svc error %d %+v", respBody.Code, respBody.Msg)
	}

	err = mapstructure.Decode(respBody.Data, &rspContent)
	if err != nil {
		return nil, err
	}

	logger.Infof("model transform rsp: %+v", rspContent)
	return &rspContent, nil
}

// 获取推理的相关信息 infer.yaml
func GetModelInferInfoformApWorkShop(modelId int64, modelVerId int64) (*protocol.ModelInferRsp, error) {
	var respBody protocol.APISuccessRsp
	var rspContent protocol.ModelInferRsp
	var client = &http.Client{
		Timeout: time.Second * 10,
	}

	url := utils.GetHttpUrl(configs.Config.Relevant.Service.ModelFactorySvc, fmt.Sprintf(ModelInferInfoUrl, modelId, modelVerId))

	logger.Infoln("get model infer.yaml url: ", url)
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	err = json.NewDecoder(resp.Body).Decode(&respBody)
	if err != nil {
		return nil, err
	}
	logger.Infof("model Id %d,  response:", modelId, respBody)

	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("get model %d info error", modelId)
	}

	d := respBody.Data.(map[string]interface{})
	rspContent.Center = d["modelVersionInference"].(map[string]interface{})["center"].(map[string]interface{})
	err = mapstructure.Decode(respBody.Data, &rspContent)
	if err != nil {
		return nil, err
	}
	return &rspContent, nil
}
